package com.tabjin.rfidsocket.authority.shiro;

import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateUtil;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTCreator;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTDecodeException;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.tabjin.rfidsocket.exception.EmosException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.util.Date;
import java.util.concurrent.TimeUnit;

/**
 * @author Tabjin
 * create at 2021/3/4 17:30
 * @program rfid_socket
 * @description
 */

@Component
@Slf4j
public class JwtUtil {

    @Autowired
    private RedisTemplate redisTemplate;

    // 密钥
    @Value("${emos.jwt.secret}")
    private String secret;

    // 过期时间（天）
    @Value("${emos.jwt.expire}")
    private Integer expire;

    // 令牌缓存时间（天）
    @Value("${emos.jwt.cache-expire}")
    private Integer cacheExpire;

    /**
     * 加密过程：生成令牌字符串
     *
     * @param userId
     * @return
     */
    public String createToken(Integer userId) {
        Date date = DateUtil.offset(new Date(), DateField.DAY_OF_YEAR, 5);// 获取到过期日期（也就是5天后）
        Algorithm algorithm = Algorithm.HMAC256(secret);// 创建加密算法
        JWTCreator.Builder builder = JWT.create();// 根据外部类创建一个内部类 builder
        String token = builder.withClaim("userId", userId) // 绑定userId
                .withExpiresAt(date) // 绑定过期时间
                .sign(algorithm);// 绑定加密算法

        saveCacheToken(token, userId);
        return token;
    }

    /**
     * 解密过程：根据 token 获取 userId
     *
     * @param token
     * @return
     */
    public Integer getUserId(String token) {
        Integer userId = null;
        try {
            DecodedJWT jwt = JWT.decode(token);// 解码对象
            userId = jwt.getClaim("userId").asInt();
        } catch (JWTDecodeException e) {
            throw new EmosException("令牌无效");
        }
        return userId;
    }

    /**
     * 验证 token 令牌
     * 验证不通过直接是抛出 Runtime 异常
     * @param token
     */
    public void verifyToken(String token) {
        Algorithm algorithm = Algorithm.HMAC256(secret); // 创建加密算法
        JWTVerifier verifier = JWT.require(algorithm).build();// 验证对象
        verifier.verify(token);
    }

    private void saveCacheToken(String token,int userId){
        redisTemplate.opsForValue().set(token,userId+"",cacheExpire, TimeUnit.DAYS);
    }
}

